package com.zhudi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhudi.model.enums.ErrorCode;
import com.zhudi.model.enums.TeamStatusEnum;
import com.zhudi.expection.BusinessException;
import com.zhudi.mapper.TeamMapper;
import com.zhudi.mapper.UserMapper;
import com.zhudi.model.entity.Team;
import com.zhudi.model.entity.User;
import com.zhudi.model.entity.UserTeam;
import com.zhudi.model.request.TeamJoinRequest;
import com.zhudi.service.UserTeamService;
import com.zhudi.mapper.UserTeamMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.zhudi.contant.TeamContant.MAX_TEAM_INTER_NUM;
import static com.zhudi.model.enums.TeamStatusEnum.ENCRYPTION;

/**
* @author 朱朱朱朱蒂
* @description 针对表【user_team(队伍表)】的数据库操作Service实现
* @createDate 2024-03-23 22:53:15
*/
@Service
public class UserTeamServiceImpl extends ServiceImpl<UserTeamMapper, UserTeam>
    implements UserTeamService{

    @Resource
    private UserTeamMapper userTeamMapper;

    @Resource
    private TeamMapper teamMapper;

    @Resource
    private UserMapper userMapper;

    @Override
    public long getUserJoinedTeamNums(Long userId) {
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id",userId);
        return userTeamMapper.selectCount(queryWrapper);

    }

    @Override
    public List<User> getTeamPlayer(Long teamId) {
        if (teamId==null){
            return null;
        }
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("team_id",teamId);

        List<UserTeam> userTeams = userTeamMapper.selectList(queryWrapper);

        List<User> result = new ArrayList<>();
        for (UserTeam userTeam : userTeams) {
            Long userId = userTeam.getUserId();
            User user = userMapper.selectById(userId);
            result.add(user);
        }
        return result;
    }

    @Override
    public Boolean isJoin(Long teamId, Long userId) {
        if (teamId==null||userId==null){
            return false;
        }
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("team_id",teamId);
        queryWrapper.eq("user_id",userId);
        //正常应该是等于1，但是防止说可能误差入两条一样的数据，所以设置为大于等于
        return userTeamMapper.selectCount(queryWrapper)>=1;


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean joinTeam(TeamJoinRequest teamJoinRequest, Long loginUserId) {

        //  1. 检验参数是否为空以及id合法性判断
        if (teamJoinRequest==null
                ||teamJoinRequest.getTeamId()==null||teamJoinRequest.getTeamId()<=0
                ||loginUserId==null||loginUserId<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        //2. 根据队伍 id，获取剩余人员数，如果小于 1 则直接返回队伍已满
        Long teamId = teamJoinRequest.getTeamId();
        Team team = teamMapper.selectById(teamId);
        int playersNum = team.getPlayersNum();
        int maxNum = team.getMaxNum();
        //todo：这部分检查的都需要加锁来防止并发冲突，包括剩余人数判断、已加入队伍判断都可以加锁
        if (playersNum==maxNum){
            //如果人员满的话，先返回false，
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍已满");
        }
        //3. 根据用户 id，检查其添加的队伍数，如果超过限定数也不允许加入
        long userTeamNums = this.getUserJoinedTeamNums(loginUserId);
        if (userTeamNums>MAX_TEAM_INTER_NUM){
            throw new BusinessException(ErrorCode.USER_ERROR,"加入队伍数过多");
        }


        //4. 再检查当前用户是否已经加入了，如果是也返回成功
        if(this.isJoin(teamId,loginUserId)){
            return true;
        }

        //5. 否则执行加入逻辑
        //	1. 首先要判断队伍是否是加密的
        TeamStatusEnum status = TeamStatusEnum.getSatus(team.getStatus());
        if (ENCRYPTION.equals(status)){
            //		1. 如果是的话取出密码，和传入的密码作比较，（ #todo 将这一步改为加密的方式）
            String password = teamJoinRequest.getPassword();
            //如果不一样直接抛异常
            if (!team.getPassword().equals(password)){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍密码错误");
            }
        }

        //	2. 如果密码一样或者不加密，那么就更新数据
        //首先往记录表更新一条记录
        UserTeam userTeam = new UserTeam(loginUserId,teamId);
        boolean result = this.save(userTeam);
        //然后要更新team的成员数+1
        team.setPlayersNum(team.getPlayersNum()+1);
        teamMapper.updateById(team);

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean quitTeam(Long teamId, Long loginUserId) {
        //  1. 参数判空
        if(teamId==null||loginUserId==null||teamId<=0||loginUserId<=0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //2. 根据队伍 id 获取对应的队伍信息
        Team team = teamMapper.selectById(teamId);
        if (team==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"要退出的队伍不存在");
        }
        //3. 判断是否只剩 1 人，如果是则删两张表记录
        int playersNum = team.getPlayersNum();
        //userTeamQueryWrapper是要删除的记录
        QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
        userTeamQueryWrapper.eq("user_id",loginUserId);
        userTeamQueryWrapper.eq("team_id",teamId);
        //要判断一下是否有加入这个队伍
        if (userTeamMapper.selectCount(userTeamQueryWrapper)==0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"当前用户并没有加入此队伍");
        }
        if(playersNum==1){
            //如果只剩一人，那么队伍也要删除
            teamMapper.deleteById(teamId);
        }else {
            //如果不是一个人，那么只需要更新一下人数，然后看是不是队长，是的话还要更新一下队长id
            if(Objects.equals(team.getLeaderId(), loginUserId)){
                //	1. 获取第二早加入的成员 id（根据 user-team 表中的创建时间）
                //TeamPlayersQueryWrapper是所有队员的记录
                QueryWrapper<UserTeam> TeamPlayersQueryWrapper = new QueryWrapper<>();
                TeamPlayersQueryWrapper.eq("team_id",teamId);
                //因为id是自增的，所以比较小的id就是比较早加入的id
                //通过id来比较比时间字段好的地方在于可以使用索引
                TeamPlayersQueryWrapper.orderByAsc("id");
                List<UserTeam> userTeams = userTeamMapper.selectList(TeamPlayersQueryWrapper);

                //获取第二早加入的队员id
                UserTeam secondTeam = userTeams.get(1);
                Long newLeaderId = secondTeam.getUserId();
                //	2. team 表成员-1、更改队长id
                team.setLeaderId(newLeaderId);

            }
            //不管是不是队长，都要队员人数-1，所以将代码抽取出来
            team.setPlayersNum(playersNum -1);
            teamMapper.updateById(team);

        }
        //	3. user-team 表删除对应记录
        //不管什么情况，最终都要删除user-team表中的记录
        ;

        //如果之前出错了，其实会事务回滚，成功的话则影响的条数是1条，防止一致性出错，设置为大于等于
        return userTeamMapper.delete(userTeamQueryWrapper)>=1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteTeam(Long teamId, Long loginUserId) {

//        1. 参数判空
        if (teamId==null||loginUserId==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍id错误或用户不存在");
        }

//        2. 查找队伍，如果找不到则tbe
        Team team = teamMapper.selectById(teamId);
        if (team==null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"没有该队伍");
        }

//        3. 鉴权，只有队长才可以解散
        Long leaderId = team.getLeaderId();
        if (!Objects.equals(leaderId,loginUserId)){
            //        5. 不是队长打回无权限。

            throw new BusinessException(ErrorCode.NO_AUTH,"只有队长才可以解散队伍");
        }
//        4. 是队长的话删除两张表记录
        teamMapper.deleteById(teamId);
        QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("team_id",teamId);

        return userTeamMapper.delete(queryWrapper)>=1;

    }


}




